package com.rc.web.service.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.rc.common.constant.Code;
import com.rc.common.exception.BusinessException;
import com.rc.common.util.PositionUtil;
import com.rc.pojo.dto.area.AreaAddDTO;
import com.rc.pojo.dto.area.AreaPageQuery;
import com.rc.pojo.dto.area.AreaSeasonalDTO;
import com.rc.pojo.dto.area.AreaUpdateDTO;
import com.rc.pojo.po.Activity;
import com.rc.pojo.po.Area;
import com.rc.pojo.po.Plant;
import com.rc.pojo.vo.area.AreaSeasonalVO;
import com.rc.pojo.vo.area.AreaVO;
import com.rc.pojo.vo.area.PageAreaVO;
import com.rc.web.converter.AreaConverter;
import com.rc.web.mapper.AreaMapper;
import com.rc.web.service.ActivityService;
import com.rc.web.service.AreaService;
import com.rc.web.service.PlantItemService;
import com.rc.web.service.PlantService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 园区服务实现类
 * 提供园区相关的业务逻辑实现
 */
@Service
@RequiredArgsConstructor
public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements AreaService {
    // 园区转换器
    private final AreaConverter areaConverter;
    // 植物服务
    private final PlantService plantService;
    // 活动服务
    private final ActivityService activityService;
    // 植物项服务
    private final PlantItemService plantItemService;

    /**
     * 添加园区
     * @param dto 园区添加DTO
     */
    @Override
    public void add(AreaAddDTO dto) {
        Area area = areaConverter.addDTO2DO(dto);

        Plant plant = plantService.getById(dto.getPlantId());

        //确认该植物是否存在
        if (plant == null){
            throw new BusinessException(Code.NO_SUCH_PLANT);
        }

        mapper.insertSelective(area);
    }

    /**
     * 根据ID删除园区
     * @param id 园区ID
     */
    @Override
    public void deleteOneById(Long id) {
        //确认该园区没有关联活动
        List<Activity> activityList = activityService.list().stream()
                .filter(activity -> id.equals(activity.getAreaId()))
                .toList();

        if (!CollectionUtils.isEmpty(activityList)){
            throw new BusinessException(Code.AREA_HAS_ACTIVITY);
        }
        //确认该园区没有关联果树

        //确认该园区存在且属于该农场
        boolean success = this.removeById(id);
        if (!success){
            throw new BusinessException(Code.NO_SUCH_AREA);
        }
    }

    /**
     * 更新园区信息
     * @param dto 园区更新DTO
     */
    @Override
    public void updateOneById(AreaUpdateDTO dto) {
        Area area = areaConverter.updateDTO2DO(dto);

        boolean success = this.updateById(area);
        if (!success){
            throw new BusinessException(Code.NO_SUCH_AREA);
        }
    }

    /**
     * 获取园区列表
     * @return 园区VO列表
     */
    @Override
    public List<AreaVO> getList() {
        List<Area> areas = mapper.selectAll();
        return areas.stream()
                .map(areaConverter::toVO)
                .collect(Collectors.toList());
    }

    /**
     * 根据ID获取园区信息
     * @param id 园区ID
     * @return 园区VO
     */
    @Override
    public AreaVO getOneById(Long id) {
        Area area = mapper.selectOneById(id);
        return areaConverter.toVO(area);
    }

    /**
     * 分页查询园区信息
     * @param dto 分页查询条件
     * @return 分页结果
     */
    @Override
    public Page<PageAreaVO> getPage(AreaPageQuery dto) {
        return mapper.selectPage(dto);
    }

    /**
     * 根据植物ID获取园区列表
     * @param plantId 植物ID
     * @return 园区列表
     */
    @Override
    public List<Area> getByPlantId(Long plantId) {
        return mapper.selectByPlantId(plantId);
    }

    /**
     * 获取季节性园区列表
     * @param dto 季节性查询条件
     * @return 季节性园区VO列表
     */
    @Override
    public List<AreaSeasonalVO> seasonal(AreaSeasonalDTO dto) {
        Double lng = dto.getLng();
        Double lat = dto.getLat();

        List<Area> areas =  mapper.selectSeasonal(dto.getFarmId(),lng, lat, dto.getDistance(),dto.getType());

        return areas.stream()
                .map(item ->{
                    AreaSeasonalVO seasonalVO = areaConverter.toSeasonalVO(item);
                    seasonalVO.setDistance(PositionUtil.distance(lng, lat,item.getLng(),item.getLat()));
                    return seasonalVO;
                })
                .toList();
    }
}
